home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
lisp
/
elk-2_0.lha
/
elk-2.0
/
src
/
dump.elf.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-21
|
9KB
|
256 lines
/* Derived from the file src/unexelf.c written by Spencer W. Thomas
* (from the Emacs 18.58 distribution), to which the following copyright
* applies:
*
* Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* In other words, you are welcome to use, share and improve this program.
* You are forbidden to forbid anyone else to use, share and improve
* what you give them. Help stamp out software-hoarding!
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <memory.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <elf.h>
#include <sys/mman.h>
/* Get the address of a particular section or program header entry,
* accounting for the size of the entries.
*/
#define OLD_SECTION_H(n) \
(*(Elf32_Shdr *) ((byte *) old_section_h + old_file_h->e_shentsize * (n)))
#define NEW_SECTION_H(n) \
(*(Elf32_Shdr *) ((byte *) new_section_h + new_file_h->e_shentsize * (n)))
#define OLD_PROGRAM_H(n) \
(*(Elf32_Phdr *) ((byte *) old_program_h + old_file_h->e_phentsize * (n)))
#define NEW_PROGRAM_H(n) \
(*(Elf32_Phdr *) ((byte *) new_program_h + new_file_h->e_phentsize * (n)))
typedef unsigned char byte;
static int round_up (x, y) int x, y; {
int rem = x % y;
if (rem == 0)
return x;
return x - rem + y;
}
Object P_Dump (ofile) Object ofile; {
unsigned int bss_end;
int new_file_size;
caddr_t old_base, new_base;
/* Pointers to the file, program and section headers for the old and new
* files.
*/
Elf32_Ehdr *old_file_h, *new_file_h;
Elf32_Phdr *old_program_h, *new_program_h;
Elf32_Shdr *old_section_h, *new_section_h;
/* Point to the section name table in the old file.
*/
char *old_section_names;
Elf32_Addr old_bss_addr, new_bss_addr;
Elf32_Word old_bss_size, new_data2_size;
Elf32_Off new_data2_offset;
Elf32_Addr new_data2_addr;
int n, old_bss_index, old_data_index, new_data2_index;
struct stat stat_buf;
Dump_Prolog;
Was_Dumped = 1;
if (fstat (afd, &stat_buf) == -1) {
Dump_Finalize;
Primitive_Error ("cannot stat old a.out file: ~E");
}
old_base = mmap (0, stat_buf.st_size, PROT_READ, MAP_SHARED, afd, 0);
if (old_base == (caddr_t)-1) {
Dump_Finalize;
Primitive_Error ("cannot mmap old a.out file: ~E");
}
/* Get pointers to headers & section names.
*/
old_file_h = (Elf32_Ehdr *) old_base;
old_program_h = (Elf32_Phdr *) ((byte *) old_base + old_file_h->e_phoff);
old_section_h = (Elf32_Shdr *) ((byte *) old_base + old_file_h->e_shoff);
old_section_names = (char *) old_base
+ OLD_SECTION_H(old_file_h->e_shstrndx).sh_offset;
/* Find the old .bss section. Figure out parameters of the new
* data2 and bss sections.
*/
for (old_bss_index = 1; old_bss_index < old_file_h->e_shnum;
old_bss_index++) {
if (strcmp (old_section_names + OLD_SECTION_H(old_bss_index).sh_name,
".bss") == 0)
break;
}
if (old_bss_index == old_file_h->e_shnum) {
Dump_Finalize;
Primitive_Error ("cannot find .bss in old a.out file");
}
old_bss_addr = OLD_SECTION_H(old_bss_index).sh_addr;
old_bss_size = OLD_SECTION_H(old_bss_index).sh_size;
new_bss_addr = (Elf32_Addr)sbrk (0);
new_data2_addr = old_bss_addr;
new_data2_size = new_bss_addr - old_bss_addr;
new_data2_offset = OLD_SECTION_H(old_bss_index).sh_offset;
if ((unsigned) new_bss_addr < (unsigned) old_bss_addr + old_bss_size) {
Dump_Finalize;
Primitive_Error (".bss shrank");
}
/* Set the output file to the right size and mmap(2) it. Set
* pointers to various interesting objects. stat_buf still has
* old_file data.
*/
new_file_size = stat_buf.st_size + old_file_h->e_shentsize + new_data2_size;
if (ftruncate (ofd, new_file_size) == -1) {
Dump_Finalize;
Primitive_Error ("cannot ftruncate new a.out file: ~E");
}
new_base = mmap (0, new_file_size, PROT_READ | PROT_WRITE, MAP_SHARED,
ofd, 0);
if (new_base == (caddr_t)-1) {
Dump_Finalize;
Primitive_Error ("cannot mmap new a.out file: ~E");
}
new_file_h = (Elf32_Ehdr *) new_base;
new_program_h = (Elf32_Phdr *) ((byte *) new_base + old_file_h->e_phoff);
new_section_h = (Elf32_Shdr *)
((byte *) new_base + old_file_h->e_shoff + new_data2_size);
/* Make our new file, program and section headers as copies of the
* originals.
*/
memcpy (new_file_h, old_file_h, old_file_h->e_ehsize);
memcpy (new_program_h, old_program_h,
old_file_h->e_phnum * old_file_h->e_phentsize);
memcpy (new_section_h, old_section_h,
old_file_h->e_shnum * old_file_h->e_shentsize);
/* Fix up file header. We'll add one section. Section header is
* further away now.
*/
new_file_h->e_shoff += new_data2_size;
new_file_h->e_shnum += 1;
/* Fix up a new program header. Extend the writable data segment so
* that the bss area is covered too. Find that segment by looking
* for a segment that ends just before the .bss area. Make sure
* that no segments are above the new .data2. Put a loop at the end
* to adjust the offset and address of any segment that is above
* data2, just in case we decide to allow this later.
*/
for (n = new_file_h->e_phnum - 1; n >= 0; n--) {
/* Compute maximum of all requirements for alignment of section.
*/
int alignment = (NEW_PROGRAM_H (n)).p_align;
if ((OLD_SECTION_H (old_bss_index)).sh_addralign > alignment)
alignment = OLD_SECTION_H (old_bss_index).sh_addralign;
if (NEW_PROGRAM_H(n).p_vaddr + NEW_PROGRAM_H(n).p_filesz
> old_bss_addr) {
Dump_Finalize;
Primitive_Error ("program segment above .bss");
}
if (NEW_PROGRAM_H(n).p_type == PT_LOAD
&& (round_up ((NEW_PROGRAM_H (n)).p_vaddr
+ (NEW_PROGRAM_H (n)).p_filesz, alignment)
== round_up (old_bss_addr, alignment)))
break;
}
if (n < 0) {
Dump_Finalize;
Primitive_Error ("cannot find segment next to .bss");
}
NEW_PROGRAM_H(n).p_filesz += new_data2_size;
NEW_PROGRAM_H(n).p_memsz = NEW_PROGRAM_H(n).p_filesz;
#if 0 /* Maybe allow section after data2 - does this ever happen? */
for (n = new_file_h->e_phnum - 1; n >= 0; n--) {
if (NEW_PROGRAM_H(n).p_vaddr
&& NEW_PROGRAM_H(n).p_vaddr >= new_data2_addr)
NEW_PROGRAM_H(n).p_vaddr += new_data2_size - old_bss_size;
if (NEW_PROGRAM_H(n).p_offset >= new_data2_offset)
NEW_PROGRAM_H(n).p_offset += new_data2_size;
}
#endif
/* Fix up section headers based on new .data2 section. Any section
* whose offset or virtual address is after the new .data2 section
* gets its value adjusted. .bss size becomes zero and new address
* is set. data2 section header gets added by copying the existing
* .data header and modifying the offset, address and size.
*/
for (n = 1; n < new_file_h->e_shnum; n++) {
if (NEW_SECTION_H(n).sh_offset >= new_data2_offset)
NEW_SECTION_H(n).sh_offset += new_data2_size;
if (NEW_SECTION_H(n).sh_addr
&& NEW_SECTION_H(n).sh_addr >= new_data2_addr)
NEW_SECTION_H(n).sh_addr += new_data2_size - old_bss_size;
}
new_data2_index = old_file_h->e_shnum;
for (old_data_index = 1; old_data_index < old_file_h->e_shnum;
old_data_index++)
if (strcmp (old_section_names + OLD_SECTION_H(old_data_index).sh_name,
".data") == 0)
break;
if (old_data_index == old_file_h->e_shnum) {
Dump_Finalize;
Primitive_Error ("cannot find .data");
}
memcpy (&NEW_SECTION_H(new_data2_index), &OLD_SECTION_H(old_data_index),
new_file_h->e_shentsize);
NEW_SECTION_H(new_data2_index).sh_addr = new_data2_addr;
NEW_SECTION_H(new_data2_index).sh_offset = new_data2_offset;
NEW_SECTION_H(new_data2_index).sh_size = new_data2_size;
NEW_SECTION_H(old_bss_index).sh_size = 0;
NEW_SECTION_H(old_bss_index).sh_addr = new_data2_addr + new_data2_size;
/* Write out the sections. .data and .data1 (and data2, called
* ".data" in the strings table) get copied from the current process
* instead of the old file.
*/
for (n = new_file_h->e_shnum - 1; n; n--) {
caddr_t src;
if (NEW_SECTION_H(n).sh_type == SHT_NULL
|| NEW_SECTION_H(n).sh_type == SHT_NOBITS)
continue;
if (strcmp (old_section_names + NEW_SECTION_H(n).sh_name,
".data") == 0 ||
strcmp ((old_section_names + NEW_SECTION_H(n).sh_name),
".data1") == 0)
src = (caddr_t) NEW_SECTION_H(n).sh_addr;
else
src = old_base + OLD_SECTION_H(n).sh_offset;
memcpy (NEW_SECTION_H(n).sh_offset + new_base, src,
NEW_SECTION_H(n).sh_size);
}
Dump_Epilog;
}